#include "Sock.hpp"
#include <poll.h>
#include <unordered_map>

#define NUM 128

void Usage(std::string proc)
{
    std::cout << "Usage \r\t" << proc << " port" << std::endl;
}

int main(int argc, char *argv[])
{
    if (argc != 2)
    {
        Usage(argv[0]);
        exit(1);
    }

    std::unordered_map<std::string, std::string> dict;
    dict["hello"] = "你好";
    dict["world"] = "世界";
    dict["apple"] = "苹果";
    dict["balana"] = "香蕉";

    int listen_sock = Sock::Socket();
    Sock::Bind(listen_sock, (uint16_t)atoi(argv[1]));
    Sock::Listen(listen_sock);

    // 此时不能直接accept，listen正在监听listen_sock对应的文件是否有读就绪
    // 为了实现select多路转接,accept是阻塞式等待

    // 初始化数据fd_array
    struct pollfd fd_array[NUM];
    for (int i = 0; i < NUM; ++i)
    {
        fd_array[i].fd = 0;
        fd_array[i].events = 0;
        fd_array[i].revents = 0;
    }

    // 将需要检测listen_sock放入结构体数组中
    fd_array[0].fd = listen_sock;
    fd_array[0].events = POLLIN;
    fd_array[0].revents = 0;

    for (;;)
    {
        // 清除上次rdset的值
        int ret = poll(fd_array, NUM, -1);
        switch (ret)
        {
        case -1:
            std::cerr << "poll errno" << std::endl;
            break;
        case 0:
            std::cout << "timeout" << std::endl;
            break;
        default:
            std::cout << "有对应文件读/写/异常就绪..." << std::endl;
            //目前已经读就绪,但是无法确定是普通文件的读就绪还是listen_sock的读就绪
            for (int i = 0; i < NUM; ++i)
            {
                if (fd_array[i].revents & POLLIN)
                {
                    std::cout << "文件描述符fd: " << fd_array[i].fd << " 读就绪" << std::endl;
                    // fd_array[i]中的文件描述符在rdset位图中对应位为1
                    // 只需判断fd_array[i]中的文件描述符是listen_sock还是普通文件
                    if (fd_array[i].fd == listen_sock)
                    {
                        // 有新链接需要获取
                        std::cout << "文件描述符fd: " << listen_sock << " 有新的链接需要获取" << std::endl;
                        int new_sock = Sock::Accept(listen_sock);
                        if (new_sock >= 0)
                        {
                            // 获取新链接成功
                            std::cout << "文件描述符fd: " << listen_sock << " 获取新链接成功" << std::endl;
                            // 此时需要把新链接的fd保存到fd_array,下次就可以检测到该fd是否有读就绪
                            // 查找fd_array中空闲位置
                            int pos;
                            for (pos = 1; pos < NUM; ++pos)
                            {
                                if (fd_array[pos].fd == 0)
                                    break;
                            }
                            if (pos < NUM)
                            {
                                // 将文件描述符放入fd_array中
                                std::cout << "新链接: " << new_sock << " 已经被添加到了数组["
                                          << pos << "]的位置" << std::endl;
                                fd_array[pos].fd = new_sock;
                                fd_array[pos].events = POLLIN;
                                fd_array[pos].revents = 0;
                            }
                            else
                            {
                                // fd_array中已经满了,没有空闲位置
                                std::cout << "系统超负荷...关闭该链接..." << std::endl;
                                close(new_sock);
                            }
                        }
                    }
                    else
                    {
                        // 普通文件读就绪
                        char read_buffer[1024];
                        ssize_t s = recv(fd_array[i].fd, read_buffer, sizeof(read_buffer) - 1, 0);
                        if (s > 0)
                        {
                            // 读取成功
                            read_buffer[s - 1] = '\0';
                            std::cout << "client[" << fd_array[i].fd << "]# " << read_buffer << std::endl;

                            // std::string message = read_buffer;
                            // std::cout << message << std::endl;
                            send(fd_array[i].fd, dict[read_buffer].c_str(), dict[read_buffer].size(), 0);
                        }
                        else if (s == 0)
                        {
                            // 客户端退出
                            std::cout << "文件描述符fd: " << fd_array[i].fd << " , exit..." << std::endl;
                            std::cout << "已经在数组下标fd_array[" << i << "]"
                                      << "中,去掉了sock: " << fd_array[i].fd << std::endl;
                            fd_array[i].events = 0;
                            fd_array[i].revents = 0;
                            close(fd_array[i].fd);
                            fd_array[i].fd = 0;
                        }
                        else
                        {
                            // 读取失败
                            fd_array[i].events = 0;
                            fd_array[i].revents = 0;
                            close(fd_array[i].fd);
                            fd_array[i].fd = 0;
                        }
                    }
                }
            }
            break;
        }
    }

    return 0;
}
